<template>
  <cross-line :text="crossText" v-model:visible="visible" />
  <el-skeleton :loading="false" animated :count="1">
    <template #default>
      <div v-show="visible">
        <div :class="$style.operate" v-if="!disabled">
          <el-button @click="addRow">{{ $t('lang.operate.increase') }}</el-button>
          <confirm
            type="button"
            link-type="danger"
            info-type="error"
            :text="$t('lang.operate.batchDelete')"
            :title="$t('lang.operate.hint')"
            :content="$t('lang.message.deleteRecords')"
            :request-data="() => removeRows(selectedRows)"
            :disabled="isDelete"
          />
        </div>
        <el-form inline :model="form" ref="nodeRef" :disabled="disabled" :rules="rules">
          <el-table
            border
            :data="form.records"
            style="width: 100%"
            ref="tableRef"
            v-loading="tabelLoading"
            :row-style="tableRowStyle"
            :max-height="maxHeight"
            @select="selectRows"
            @select-all="selectRows"
          >
            <el-table-column type="selection" fixed />
            <el-table-column type="index" :label="$t('lang.table.index')" />
            <column
              v-for="column of columns"
              :key="column.key"
              :column="column"
              :form="form"
              :disabled="disabled"
              :rules="rules"
              :initial-values="form.records"
              :options="options"
            />
            <el-table-column
              fixed="right"
              :label="$t('lang.operate.name')"
              align="center"
              width="100"
              v-if="isOperate"
            >
              <template #default="{ row, $index }">
                <el-form-item>
                  <el-button v-if="!row.id" type="text" @click="onSave(row, $index)">{{
                    $t('lang.operate.save')
                  }}</el-button>
                  <el-button v-if="row.id" type="text" @click="onUpdate(row, $index)">{{
                    $t('lang.operate.update')
                  }}</el-button>
                  <confirm
                    type="button"
                    link-type="text"
                    info-type="error"
                    :text="$t('lang.operate.delete')"
                    :title="$t('lang.operate.hint')"
                    :class="$style['error-text']"
                    :content="$t('lang.message.deleteRecords')"
                    :request-data="() => removeRows([row])"
                  />
                </el-form-item>
              </template>
            </el-table-column>
          </el-table>
        </el-form>
        <el-pagination
          class="pagination"
          v-if="pagination"
          v-model:current-page="pagination.pageNum"
          v-model:page-size="pageSize"
          layout="total, prev, pager, next, jumper"
          :total="total"
          background
          @current-change="currentChange"
        />
      </div>
    </template>
  </el-skeleton>
</template>

<script lang="ts">
import useValidate from '@/hooks/useValidate'
import CrossLine from './CrossLine.vue'
import { computed, PropType, reactive, ref, defineComponent, onMounted, toRefs } from 'vue'
import { EditColumn } from '@/components/Records/types'
import Column from './Column.vue'
import useSearch from '@/hooks/useSearch'
import { map, differenceBy, isEmpty, get, reduce, filter, find } from 'lodash'
import { FormItemKey, ObjectType, ResponseDataPromise } from 'typings/interfaces'
import { useI18n } from 'vue-i18n'
import { OperateTypes } from '@/enums/operateTypes'
import { ElMessage } from 'element-plus'
import Confirm from '@/components/Confirm/index.vue'
import { handleFormItems } from '@/utils/util'
import useRender from '../hooks/useRender'
import { fnFormatting, stakeToValue } from '@/utils/formatting.js'

/* 记录状态 */
enum Flag {
  add = 1,
  upadated = 2,
}

/* 部分表单校验 */
const validateFields = (form: Record<FormItemKey, any>, index: number, validate) => {
  let errorMsg: Array<string> = []
  const validateKeys = reduce<Record<FormItemKey, keyof any>, string[]>(
    form,
    (total, value, key) => [...total, `records.${index}.${key}`],
    []
  )
  return new Promise((resolve, reject) => {
    validate(validateKeys, (msg: string | undefined) => {
      if (msg) {
        errorMsg?.push(msg)
      }
    })
    isEmpty(errorMsg) ? resolve(true) : reject(errorMsg)
  })
}

export default defineComponent({
  name: 'Records',
  emits: ['update:modelValue'],
  components: {
    CrossLine,
    Column,
    Confirm,
  },
  props: {
    idObj: {
      // 草稿状态下，编辑，添加需要的主表的id键值对。
      type: Object as PropType<Record<string, string>>,
      required: true,
    },
    crossText: {
      type: String,
      required: true,
    },
    columns: {
      type: Array as PropType<EditColumn[]>,
      required: true,
    },
    options: {
      type: Object as PropType<ObjectType>,
      default: () => ({}),
    },
    maxHeight: {
      type: Number,
      default: 500,
    },
    operateType: {
      type: String as PropType<OperateTypes | null>,
      required: true,
    },
    disabled: {
      type: Boolean,
      required: true,
    },
    isOpened: {
      type: Boolean,
      required: true,
    },
    rules: {
      type: Object as PropType<Record<FormItemKey, Array<ObjectType>>>,
      default: () => ({}),
    },
    fetchRecord: {
      type: Function as PropType<(...parmas: any) => ResponseDataPromise<ObjectType>>,
      required: true,
    },
    updateRecord: {
      type: Function as PropType<(...parmas: any) => ResponseDataPromise<boolean>>,
      required: true,
    },
    deleteRecords: {
      type: Function as PropType<(parmas: string[]) => ResponseDataPromise<boolean>>,
      required: true,
    },
    addRecord: {
      type: Function as PropType<(...parmas: any) => ResponseDataPromise<string>>,
      required: true,
    },
  },
  setup(props, { emit }) {
    const { isOpened } = toRefs(props)
    const { t } = useI18n()
    const { nodeRef } = useValidate()
    const asyncRender = useRender(isOpened)
    const row = handleFormItems(props.columns)

    const form = reactive<any>({ records: [] })
    const tableRef = ref<null | ObjectType>(null)
    const selectedRows = ref<ObjectType[]>([])
    const total = ref<number>(0)
    const pageSize = ref<number>(15)

    const selectRows = (selection: ObjectType[]) => (selectedRows.value = selection)

    const { loading, pagination, dataSource, changePage } = useSearch(props.fetchRecord, {
      notImmediate: true,
      extraParams: props.idObj,
    })

    const successMessage = () =>
      ElMessage.success({
        message: t('lang.message.operateSuccess'),
        type: 'success',
      })
    const addRow = () => {
      form.records.unshift({ ...row, _flag: Flag.add })
      total.value += 1
      pageSize.value += 1
    }

    onMounted(() => {
      nodeRef.value?.resetFields()
      if (props.operateType !== OperateTypes.ADD && props.addRecord) {
        changePage(1).then((data) => {
          form.records = data
          for (let k in form.records) {
            form.records[k].endStake = fnFormatting(form.records[k].endStake)
            form.records[k].startStake = fnFormatting(form.records[k].startStake)
            form.records[k].centerStake = fnFormatting(form.records[k].centerStake)
          }
          total.value = pagination.total
        })
      }
    })

    /* 分页 */
    const currentChange = (page: number) =>
      changePage(page).then((data) => {
        pageSize.value = 15
        form.records = data
      })

    /* 保存数据 */
    const onSave = (row: ObjectType, index: number) =>
      validateFields(row, index, nodeRef.value?.validateField).then(() => {
        row.startStake = stakeToValue(row?.startStake)
        row.endStake = stakeToValue(row?.endStake)
        row.centerStake = stakeToValue(row?.centerStake)
        props.addRecord({ ...row, ...props.idObj }).then(({ data }) => {
          // 更新子清单项
          row.startStake = fnFormatting(row.startStake)
          row.endStake = fnFormatting(row.endStake)
          row.centerStake = fnFormatting(row.centerStake)
          form.records[index] = { ...row, id: get(data, 'data'), ...props.idObj }
          emit('update:modelValue', form.records)
          successMessage()
        })
      })

    /* 更新数据 */
    const onUpdate = (data: ObjectType, index: number) =>
      validateFields(row, index, nodeRef.value?.validateField).then(() => {
        data.startStake = stakeToValue(data?.startStake)
        data.endStake = stakeToValue(data?.endStake)
        data.centerStake = stakeToValue(data?.centerStake)
        props.updateRecord({ ...data, ...props.idObj }).then(() => {
          form.records[index]._flag = Flag.upadated
          form.records[index].endStake = fnFormatting(form.records[index].endStake)
          form.records[index].startStake = fnFormatting(form.records[index].startStake)
          form.records[index].centerStake = fnFormatting(form.records[index].centerStake)
          emit('update:modelValue', form.records)
          successMessage()
        })
      })

    /* 移除行数据 */
    const remove = (rows: ObjectType[]) => {
      const flagRows = differenceBy(
        filter(form.records, ({ _flag }) => _flag),
        rows,
        '_flag'
      )
      if (props.operateType !== OperateTypes.ADD) {
        changePage(pagination.pageNum).then((data) => {
          const records = map(data, (item) =>
            find(flagRows, { id: item.id }) ? { ...item, _falg: 2 } : item
          )
          form.records = records
          total.value = pagination.total
          pageSize.value = 15
        })
      } else {
        pageSize.value -= rows.length
        form.records = differenceBy(form.records, rows)
      }
      total.value -= rows.length
      successMessage()
      selectedRows.value = []
    }

    // 批量删除子清单项
    const removeRows = (rows: ObjectType[]) => {
      const value = get(Object.values(props.idObj), '0')
      const ids = reduce<ObjectType, string[]>(
        rows,
        (total, current) => {
          if (current.id) return [...total, current.id]
          return total
        },
        []
      )
      return new Promise((resolve, reject) => {
        // 草稿状态下删除子清单
        if (value && !isEmpty(ids)) {
          props.deleteRecords(ids).then(() => {
            remove(rows)
            resolve(true)
          })
        } else {
          remove(rows)
          reject(false)
        }
      })
    }

    const tableRowStyle = ({ row }) => {
      if (props.operateType !== OperateTypes.ADD) {
        if (row._flag) {
          return {
            background: '#f9e498',
          }
        }
      }
    }

    return {
      pagination,
      dataSource,
      tabelLoading: loading,
      visible: asyncRender.visible,
      loading: asyncRender.loading,
      currentChange,
      isDelete: computed(() => isEmpty(selectedRows.value)),
      isOperate: computed(
        () => props.operateType === OperateTypes.EDIT || props.operateType === OperateTypes.APPROVAL
      ), // 是否操作行
      onSave,
      onUpdate,
      nodeRef,
      changePage,
      form,
      tableRef,
      addRow,
      selectRows,
      selectedRows,
      removeRows,
      tableRowStyle,
      total,
      pageSize,
    }
  },
})
</script>
<style module lang="scss">
.operate {
  margin: 10px 0;
}
.error-text {
  span {
    color: #f56c6c;
  }
}
</style>
